/*
 * Copyright (C) 2008 Apple Computer, Inc.  All rights reserved.
 * Copyright (C) 2012 Sony Computer Entertainment Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "FrameLoaderClientManx.h"

#include "BackForwardList.h"
#include "DocumentLoader.h"
#include "FormState.h"
#include "Frame.h"
#include "FrameLoaderTypes.h"
#include "FrameNetworkingContextManx.h"
#include "FrameTree.h"
#include "FrameView.h"
#include "HTMLFormElement.h"
#include "HTMLFrameOwnerElement.h"
#include "MIMETypeRegistry.h"
#include "NotImplemented.h"
#include "Page.h"
#include "ProgressTracker.h"
#include "RenderPart.h"
#include "ResourceError.h"
#include "ResourceHandleManager.h"
#include "ResourceResponse.h"
#include "SchemeRegistry.h"
#include "ScriptController.h"
#include "Settings.h"
#include "WebViewJavaScriptObject.h"
#include "WebViewPrivate.h"
#include <JavaScriptCore/APICast.h>
#include <JavaScriptCore/JavaScript.h>
#include <JavaScriptCore/OpaqueJSString.h>
#include <manx/LoadTypes.h>
#include <stdio.h>
#include <webkit/WebView.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
#include <wtf/text/WTFString.h>

#if ENABLE(TILED_BACKING_STORE)
#include "TiledBackingStore.h"
#endif

namespace WebCore {

static FrameLoaderClientManx* gFrameLoaderClient = 0;
enum {
    SecurityStatus_None = 0, // None
    SecurityStatus_NonSecured, // Non secured
    SecurityStatus_Secured, // Secured
    SecurityStatus_Mixed, // Mixed
};

FrameLoaderClientManx::FrameLoaderClientManx(WebKit::WebViewPrivate* webView)
    : m_webView(webView)
    , m_frame(0)
    , m_hasRepresentation(false)
    , m_securityStatus(SecurityStatus_None)
{
    m_cert = 0;
}

FrameLoaderClientManx::~FrameLoaderClientManx()
{
}

void FrameLoaderClientManx::frameLoaderDestroyed()
{
    m_webView = 0;
    m_frame = 0;
#if OS(PSP2)
    if (m_cert) {
        delete reinterpret_cast<Manx::X509chain*>(m_cert);
        m_cert = 0;
    }

#endif
    delete this;
}

bool FrameLoaderClientManx::hasWebView() const
{
    return true;
}

void FrameLoaderClientManx::makeRepresentation(DocumentLoader*)
{
    m_hasRepresentation = true;
}

void FrameLoaderClientManx::forceLayout()
{
    notImplemented();
}

void FrameLoaderClientManx::forceLayoutForNonHTML()
{
    notImplemented();
}

void FrameLoaderClientManx::setCopiesOnScroll()
{
    notImplemented();
}

void FrameLoaderClientManx::detachedFromParent2()
{
    notImplemented();
}

void FrameLoaderClientManx::detachedFromParent3()
{
    notImplemented();
}

void FrameLoaderClientManx::assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse)
{
    notImplemented();
}

bool FrameLoaderClientManx::shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier)
{
    notImplemented();
    return false;
}

void FrameLoaderClientManx::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge& challenge)
{
    Credential cred = challenge.proposedCredential();
    ProtectionSpace space = challenge.protectionSpace();
    bool toSave = false;
    String user;
    String pass;

    if (httpAuthenticationChallenge(space.host(), space.realm(), user, pass, toSave)) {
        challenge.m_user = user;
        challenge.m_pass = pass;
        challenge.m_ok = true;
    }
}

void FrameLoaderClientManx::dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&)
{
    notImplemented();
}

#if PLATFORM(MANX)
bool FrameLoaderClientManx::httpAuthenticationChallenge(const String& siteUrl, const String& message, String& user, String& password, bool& updatedSavedFlag)
{
    WebKit::WebString webUser = user;
    WebKit::WebString webPassword = password;
    bool ok = m_webView->client().httpAuthenticationChallenge(siteUrl, message, webUser, webPassword);
    user = webUser;
    password = webPassword;
    return ok;
}
#endif

void FrameLoaderClientManx::dispatchDidReceiveResponse(DocumentLoader* loader, unsigned long id, const ResourceResponse& response)
{
    bool isSecure = (response.url().protocol() == "https");
    switch (m_securityStatus) {
    case SecurityStatus_None:
        if (isSecure)
            m_securityStatus = SecurityStatus_Secured;
        else
            m_securityStatus = SecurityStatus_NonSecured;
        break;
    case SecurityStatus_NonSecured:
        if (isSecure)
            m_securityStatus = SecurityStatus_Mixed;
        break;
    case SecurityStatus_Secured:
        if (!isSecure)
            m_securityStatus = SecurityStatus_Mixed;
        break;
    default:
        break;
    }

    if (loader->isLoadingMainResource() && !response.replaceUrl().isEmpty())
        loader->replaceRequestURLForSameDocumentNavigation(response.replaceUrl());

#if OS(PSP2)
    if (response.isMainResource() && response.cert()) {
        if (m_cert)
            delete reinterpret_cast<Manx::X509chain*>(m_cert);
        m_cert = new Manx::X509chain(reinterpret_cast<Manx::X509chain*>(response.cert()));
    }
#endif
}

void FrameLoaderClientManx::dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived)
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier)
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError& error)
{
    notImplemented();
}

bool FrameLoaderClientManx::dispatchDidLoadResourceFromMemoryCache(DocumentLoader* loader, const ResourceRequest& request, const ResourceResponse& response, int length)
{
    notImplemented();
    return true;
}

void FrameLoaderClientManx::dispatchDidHandleOnloadEvents()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidReceiveServerRedirectForProvisionalLoad()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidCancelClientRedirect()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchWillPerformClientRedirect(const KURL&, double interval, double fireDate)
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidNavigateWithinPage()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidChangeLocationWithinPage()
{
    // check if this frame is the main frame, otherwise do nothing for now
    if (m_webView->m_frame != m_frame)
        return;
    m_webView->client().didLocationChanged(m_frame->document()->url().string());
}

void FrameLoaderClientManx::dispatchDidPushStateWithinPage()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidReplaceStateWithinPage()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidPopStateWithinPage()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchWillClose()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidReceiveIcon()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidStartProvisionalLoad()
{
}

void FrameLoaderClientManx::dispatchDidReceiveTitle(const StringWithDirection& title)
{
    // check if this frame is the main frame, otherwise do nothing for now
    if (m_webView->m_frame != m_frame)
        return;
    m_webView->client().didReceiveTitle(title.string());
}

void FrameLoaderClientManx::dispatchDidChangeIcons(WebCore::IconType)
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidCommitLoad()
{
    // check if this frame is the main frame, otherwise do nothing for now
    if (m_webView->m_frame != m_frame)
        return;

    m_webView->didCommitLoad();
    m_webView->client().didCommitLoad();
    m_webView->client().didLocationChanged(m_frame->document()->url().string());
}

void FrameLoaderClientManx::dispatchDidFailProvisionalLoad(const ResourceError& error)
{
    dispatchDidFailLoad(error);
}

void FrameLoaderClientManx::dispatchDidFailLoad(const ResourceError& error)
{
    if (error.shouldCertificateVerify()) {
        bool ok = m_webView->client().verifyCertificate((int)error.sslError(), static_cast<Manx::X509chain*>(error.cert()));
        error.setConfirmCert(ok);
    } else {

        // check if this frame is the main frame, otherwise do nothing for now
        if (m_webView->m_frame != m_frame)
            return;

        if (!error.isCancellation())
            m_webView->client().didLoadFailed(error.errorCode(), error.domain(), error.failingURL(), error.localizedDescription());
    }
}

void FrameLoaderClientManx::dispatchDidFinishDocumentLoad()
{
}

void FrameLoaderClientManx::dispatchDidFinishLoad()
{
}

void FrameLoaderClientManx::dispatchDidFirstLayout()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidFirstVisuallyNonEmptyLayout()
{
}

Frame* FrameLoaderClientManx::dispatchCreatePage(const NavigationAction& action)
{
    Frame* newFrame = 0;
    if (m_frame) {
        CString url = action.url().string().utf8();
        int width = m_frame->view() ? m_frame->view()->frameRect().width() : 0;
        int height = m_frame->view() ? m_frame->view()->frameRect().height() : 0;
        WebKit::WebView* webview = m_webView->client().createWindow(url.data(), width, height, false);
        if (webview) {
            WebKit::WebViewPrivate* webViewPriv = static_cast<WebKit::WebViewPrivate*>(webview);
            newFrame = webViewPriv->m_page->mainFrame();
            // set useragent of parent webview.
            webViewPriv->setUserAgent(m_webView->userAgent());
        }
    }
    return newFrame;
}

void FrameLoaderClientManx::dispatchShow()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDecidePolicyForResponse(FramePolicyFunction function, const ResourceResponse& response, const ResourceRequest& request)
{
    if (canShowMIMEType(response.mimeType()) || !response.mimeType())
        (m_frame->loader()->policyChecker()->*function)(PolicyUse);
    else {
        m_webView->client().startDownload(request.url().string(), response.mimeType());
        // PolicyIgnore is used instread of PolicyDownload so that unsed ResourceHandle will be canceled
        (m_frame->loader()->policyChecker()->*function)(PolicyIgnore);
    }
}

void FrameLoaderClientManx::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction function, const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, const String& frameName)
{
    notImplemented();
    (m_frame->loader()->policyChecker()->*function)(PolicyUse);
}

void FrameLoaderClientManx::dispatchDecidePolicyForNavigationAction(FramePolicyFunction function, const NavigationAction& navigationAction, const ResourceRequest& res, PassRefPtr<FormState>)
{
    bool supportScheme = false;
    PolicyAction action = PolicyIgnore;
    bool handleRequest = false;
    bool isMainDoc = (m_frame && m_frame->page()->mainFrame() == m_frame);
    NavigationType type = navigationAction.type();

    if (!res.isNull()) {
        handleRequest = true;
        if (isMainDoc)
            handleRequest = m_webView->client().decidePolicyForNavigationAction(res.url().string(), type);
    }

    if (handleRequest) {
        // http, https
        WTF::String scheme = res.url().protocol();
        supportScheme = WebCore::SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(scheme);
        // about
        supportScheme |= WebCore::SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(scheme);
        // file
        supportScheme |= WebCore::SchemeRegistry::shouldTreatURLSchemeAsLocal(scheme);
        // data
        supportScheme |= WebCore::SchemeRegistry::shouldTreatURLSchemeAsNoAccess(scheme);

        if (!supportScheme)
            m_webView->client().notifyUnsupportScheme(res.url().string());
        else
            action = PolicyUse;

        bool allowed = true;
        if (isMainDoc) {
            WebCore::KURL reqUrl = res.url();
            WebCore::KURL srcUrl(m_frame->document()->url());
            bool nextIsSecure = reqUrl.protocolIs("https");
            bool prevIsSecure = srcUrl.protocolIs("https");

            if (type == NavigationTypeFormResubmitted)
                allowed = m_webView->client().decidePolicyForNavigationWarning(NAVIGATION_WARNING_EVENT_TYPE_POSTING_FROM_CACHE);
            else if (res.getRedirected() && !nextIsSecure && prevIsSecure)
                allowed = m_webView->client().decidePolicyForNavigationWarning(NAVIGATION_WARNING_EVENT_TYPE_LEAVING_SECURE_SITE_AT_REDIRECTION);
        }
        if (!allowed)
            action = WebCore::PolicyIgnore;
    }

    (m_frame->loader()->policyChecker()->*function)(action);
}

void FrameLoaderClientManx::cancelPolicyCheck()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchUnableToImplementPolicy(const ResourceError&)
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchWillSendSubmitEvent(PassRefPtr<FormState>)
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchWillSubmitForm(FramePolicyFunction function, PassRefPtr<FormState>)
{
    notImplemented();
    (m_frame->loader()->policyChecker()->*function)(PolicyUse);
}

void FrameLoaderClientManx::revertToProvisionalState(DocumentLoader*)
{
    m_hasRepresentation = true;
}

void FrameLoaderClientManx::setMainDocumentError(DocumentLoader*, const ResourceError&)
{
    notImplemented();
}

void FrameLoaderClientManx::postProgressStartedNotification()
{
    // check if this frame is the main frame, otherwise do nothing for now
    if (m_webView->m_frame != m_frame)
        return;

    m_webView->client().notifyLoadStarted(static_cast<void*>(m_frame));
}

void FrameLoaderClientManx::postProgressEstimateChangedNotification()
{
    // check if this frame is the main frame, otherwise do nothing for now
    if (m_webView->m_frame != m_frame)
        return;

    float progress = (float)m_webView->m_page->progress()->estimatedProgress();
    m_webView->client().notifyLoadProgress(progress);
}

void FrameLoaderClientManx::postProgressFinishedNotification()
{
    // check if this frame is the main frame, otherwise do nothing for now
    if (m_webView->m_frame != m_frame)
        return;

    WebCore::ResourceHandleManager::sharedInstance()->saveCookies();

    m_webView->client().notifyLoadSecurityStatus(m_securityStatus);
    m_securityStatus = SecurityStatus_None;

    m_webView->client().notifyLoadFinished();
}

ObjectContentType FrameLoaderClientManx::objectContentType(const KURL& url, const String& mimeType, bool shouldPreferPlugInsForImages)
{
    // FIXME: once plugin support is enabled, this method needs to correctly handle the 'shouldPreferPlugInsForImages' flag. See
    // WebCore::FrameLoader::defaultObjectContentType() for an example.
    UNUSED_PARAM(shouldPreferPlugInsForImages);

    if (url.isEmpty() && mimeType.isEmpty())
        return ObjectContentNone;

    // We don't use MIMETypeRegistry::getMIMETypeForPath() because it returns "application/octet-stream" upon failure
    String type = mimeType;
    if (type.isEmpty())
        type = MIMETypeRegistry::getMIMETypeForExtension(url.path().substring(url.path().reverseFind('.') + 1));

    if (type.isEmpty())
        return ObjectContentFrame;

    if (MIMETypeRegistry::isSupportedImageMIMEType(type))
        return ObjectContentImage;

#if 0 // PluginDatabase is disabled until we have Plugin system done.
    if (PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType))
        return ObjectContentNetscapePlugin;
#endif

    if (MIMETypeRegistry::isSupportedNonImageMIMEType(type))
        return ObjectContentFrame;

    if (url.protocol() == "about")
        return ObjectContentFrame;

    return ObjectContentNone;
}

void FrameLoaderClientManx::setMainFrameDocumentReady(bool)
{
    notImplemented();
}

void FrameLoaderClientManx::startDownload(const ResourceRequest&, const String& suggestedName)
{
    notImplemented();
}

void FrameLoaderClientManx::willChangeTitle(DocumentLoader*)
{
    // not used: see dispatchDidReceiveTitle
}

void FrameLoaderClientManx::didChangeTitle(DocumentLoader*)
{
    // not used: see dispatchDidReceiveTitle
}

void FrameLoaderClientManx::committedLoad(WebCore::DocumentLoader* loader, const char* data, int length)
{
    loader->commitData(data, length);
}

void FrameLoaderClientManx::finishedLoading(DocumentLoader* documentLoader)
{
    // This is necessary to create an empty document,
    // but it has to be skipped in the provisional phase.
    if (m_hasRepresentation)
        documentLoader->writer()->setEncoding("", false);
}

void FrameLoaderClientManx::updateGlobalHistory()
{
    updateGlobalHistoryItemForPage();
}

void FrameLoaderClientManx::updateGlobalHistoryRedirectLinks()
{
    notImplemented();
}

void FrameLoaderClientManx::updateGlobalHistoryItemForPage()
{
    m_webView->client().notifyHistoryChanged(m_webView->canGoBack(), m_webView->canGoForward());
}

bool FrameLoaderClientManx::shouldGoToHistoryItem(HistoryItem*) const
{
    return true;
}

bool FrameLoaderClientManx::shouldStopLoadingForHistoryItem(WebCore::HistoryItem*) const
{
    return true;
}

void FrameLoaderClientManx::didDisplayInsecureContent()
{
    notImplemented();
}

void FrameLoaderClientManx::didRunInsecureContent(SecurityOrigin*, const KURL&)
{
    notImplemented();
}

void FrameLoaderClientManx::didDetectXSS(const KURL&, bool didBlockEntirePage)
{
    notImplemented();
}

ResourceError FrameLoaderClientManx::cancelledError(const ResourceRequest& request)
{
    return ResourceError(WebKitError,
        LOAD_ERROR_CANCELLED,
        request.url().string(),
        String("Load cancelled"));
}

ResourceError FrameLoaderClientManx::blockedError(const ResourceRequest& request)
{
    return ResourceError(WebKitError,
        LOAD_ERROR_BLOCKED,
        request.url().string(),
        String("Load blocked"));
}

ResourceError FrameLoaderClientManx::cannotShowURLError(const ResourceRequest& request)
{
    return ResourceError(WebKitError,
        LOAD_ERROR_CANNOT_SHOW_URL,
        request.url().string(),
        String("Cannot show url"));
}

ResourceError FrameLoaderClientManx::interruptedForPolicyChangeError(const ResourceRequest& request)
{
    return ResourceError(WebKitError,
        LOAD_ERROR_INTERRUPTED_FOR_POLICY_CHANGE,
        request.url().string(),
        String("Interrupted for policy change"));
}

ResourceError FrameLoaderClientManx::cannotShowMIMETypeError(const ResourceResponse& response)
{
    return ResourceError(WebKitError,
        LOAD_ERROR_CANNOT_SHOW_MIME_TYPE,
        response.url().string(),
        String("Cannot show mime type"));
}

ResourceError FrameLoaderClientManx::fileDoesNotExistError(const ResourceResponse& response)
{
    return ResourceError(WebKitError,
        LOAD_ERROR_FILE_DOES_NOT_EXIST,
        response.url().string(),
        String("File does not exist"));
}

ResourceError FrameLoaderClientManx::pluginWillHandleLoadError(const ResourceResponse& response)
{
    return ResourceError(WebKitError,
        LOAD_ERROR_PLUGIN_WILL_HANDLE_LOAD,
        response.url().string(),
        String("Plugin will handle load"));
}

bool FrameLoaderClientManx::shouldFallBack(const ResourceError&)
{
    notImplemented();
    return false;
}

bool FrameLoaderClientManx::canHandleRequest(const ResourceRequest& request) const
{
    bool handleRequest = true;
    return handleRequest;
}

bool FrameLoaderClientManx::canShowMIMEType(const String& MIMEType) const
{
    if (MIMETypeRegistry::isSupportedImageMIMEType(MIMEType))
        return true;

    if (MIMETypeRegistry::isSupportedNonImageMIMEType(MIMEType))
        return true;

#if 0 // PluginDatabase is disabled until we have Plugin system done.
    if (PluginDatabase::installedPlugins()->isMIMETypeRegistered(MIMEType))
        return true;
#endif

    return false;
}

bool FrameLoaderClientManx::canShowMIMETypeAsHTML(const String& MIMEType) const
{
    notImplemented();
    return false;
}

bool FrameLoaderClientManx::representationExistsForURLScheme(const String& URLScheme) const
{
    notImplemented();
    return false;
}

String FrameLoaderClientManx::generatedMIMETypeForURLScheme(const String& URLScheme) const
{
    notImplemented();
    return String();
}

void FrameLoaderClientManx::frameLoadCompleted()
{
    notImplemented();
}

void FrameLoaderClientManx::saveViewStateToItem(HistoryItem*)
{
    notImplemented();
}

void FrameLoaderClientManx::restoreViewState()
{
    notImplemented();
}

void FrameLoaderClientManx::provisionalLoadStarted()
{
    notImplemented();
}

void FrameLoaderClientManx::didFinishLoad()
{
    notImplemented();
}

void FrameLoaderClientManx::prepareForDataSourceReplacement()
{
    notImplemented();
}

WTF::PassRefPtr<DocumentLoader> FrameLoaderClientManx::createDocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData)
{
    return DocumentLoader::create(request, substituteData);
}

void FrameLoaderClientManx::setTitle(const StringWithDirection& title, const KURL& url)
{
    // not used: see dispatchDidReceiveTitle
}

String FrameLoaderClientManx::userAgent(const KURL&)
{
    return m_webView->userAgent();
}

void FrameLoaderClientManx::savePlatformDataToCachedFrame(CachedFrame*)
{
    notImplemented();
}

void FrameLoaderClientManx::transitionToCommittedFromCachedFrame(CachedFrame*)
{
    notImplemented();
}

void FrameLoaderClientManx::transitionToCommittedForNewPage()
{
    ASSERT(m_webView);
    ASSERT(m_frame);

    IntSize size = IntSize(m_webView->m_textureWidth, m_webView->m_textureHeight);
    bool transparent = false; // FIXME: get setting from WebView
    Color backgroundColor = transparent ? WebCore::Color::transparent : WebCore::Color::white;

#if USE_TILED_BUFFER
    // If this is a main frame, clear the tiled buffers.
    if (m_webView->m_frame == m_frame) {
        IntSize fixedLayoutSize = m_webView->m_viewSize;
        m_webView->m_tiledBufferPainter->clear();
        m_webView->m_tiledBufferPainter->setContentsScale(0.0f);

        m_frame->createView(size, backgroundColor, transparent, fixedLayoutSize, IntRect(), !fixedLayoutSize.isEmpty());
        m_frame->view()->setDelegatesScrolling(true);
    } else
        m_frame->createView(size, backgroundColor, transparent);
#else
    m_frame->createView(size, backgroundColor, transparent);
#endif

#if ENABLE(TILED_BACKING_STORE)
    m_frame->view()->setDelegatesScrolling(m_frame->tiledBackingStore());
    if (m_frame->tiledBackingStore()) {
        m_frame->tiledBackingStore()->setTileSize(IntSize(256, 256));
        m_frame->view()->setFixedVisibleContentRect(IntRect(IntPoint::zero(), size));
    }
#endif
}

void FrameLoaderClientManx::didSaveToPageCache()
{
    notImplemented();
}

void FrameLoaderClientManx::didRestoreFromPageCache()
{
    notImplemented();
}

void FrameLoaderClientManx::dispatchDidBecomeFrameset(bool)
{
    notImplemented();
}

bool FrameLoaderClientManx::canCachePage() const
{
    notImplemented();
    return false;
}

void FrameLoaderClientManx::convertMainResourceLoadToDownload(WebCore::DocumentLoader* documentLoader, const ResourceRequest& request, const ResourceResponse& response)
{
}

PassRefPtr<Frame> FrameLoaderClientManx::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight)
{
    ASSERT(m_webView);
    ASSERT(m_frame);

    FrameLoaderClientManx* loaderClient = new FrameLoaderClientManx(m_webView);
    RefPtr<Frame> childFrame = Frame::create(m_webView->m_page.get(), ownerElement, loaderClient);
    loaderClient->setFrame(childFrame.get());

    childFrame->tree()->setName(name);
    m_frame->tree()->appendChild(childFrame.get());
    childFrame->init();

    // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
    if (!childFrame->page())
        return 0;

    m_frame->loader()->loadURLIntoChildFrame(url, referrer, childFrame.get());

    // The frame's onload handler may have removed it from the document.
    if (!childFrame->tree()->parent())
        return 0;

    return childFrame.release();
}

PassRefPtr<Widget> FrameLoaderClientManx::createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool loadManually)
{
    notImplemented();
    return 0;
}

void FrameLoaderClientManx::redirectDataToPlugin(Widget* pluginWidget)
{
    notImplemented();
}

PassRefPtr<Widget> FrameLoaderClientManx::createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL& baseURL, const Vector<String>& paramNames, const Vector<String>& paramValues)
{
    notImplemented();
    return 0;
}

String FrameLoaderClientManx::overrideMediaType() const
{
    notImplemented();
    return String();
}

JSValueRef FrameLoaderClientManx::jsDelegate(JSContextRef ctx, JSObjectRef function, size_t argumentCount, const JSValueRef arguments[])
{
    JSStringRef funcStr = JSValueToStringCopy(ctx, function, 0);
    unsigned strSize = funcStr->length() + 1;
    char* buffer = new char[strSize];
    size_t copySize = JSStringGetUTF8CString(funcStr, buffer, strSize);

    String subFunc(buffer);
    size_t subFuncHead = sizeof("function ") - 1;
    size_t subFuncSize = subFunc.find(")") - 1 - subFuncHead;
    String subFuncName = subFunc.substring(subFuncHead, subFuncSize);
    WebViewJavaScriptObjectDelegate delegate(subFuncName.utf8().data(), argumentCount);
    delete[] buffer;

    for (int i = 0; i < argumentCount; i++) {
        switch (JSValueGetType(ctx, arguments[i])) {
        case kJSTypeBoolean:
            delegate.args[i].type = JSTYPE_BOOLEAN;
            delegate.args[i].argBool = JSValueToBoolean(ctx, arguments[i]);
            break;
        case kJSTypeNumber:
            delegate.args[i].type = JSTYPE_NUMBER;
            delegate.args[i].argDouble = JSValueToNumber(ctx, arguments[i], 0);
            break;
        case kJSTypeString:
            {
            JSStringRef funcStr = JSValueToStringCopy(ctx, arguments[i], 0);
            unsigned strSize = funcStr->length() + 1;
            char* buffer = new char[strSize];
            size_t copySize = JSStringGetUTF8CString(funcStr, buffer, strSize);
            delegate.args[i].type = JSTYPE_STRING;
            delegate.args[i].argString = new char[strlen(buffer) + 1];
            strncpy(delegate.args[i].argString, buffer, strSize);
            delete[] buffer;
            }
            break;
        default:
            break;
        }
    }

    int returnType = 0;
    double value = 0;
    WebKit::WebString string;
    m_webView->client().didFunctionCalled(delegate, returnType, value, string);

    JSValueRef ret = JSValueMakeNull(ctx);
    switch (returnType) {
    case JSTYPE_NUMBER:
        ret = JSValueMakeNumber(ctx, value);
        break;
    case JSTYPE_STRING:
        {
            JSStringRef objName = JSStringCreateWithCharacters(string.data(), string.length());
            ret = JSValueMakeString(ctx, objName);
            JSStringRelease(objName);
        }
        break;
    default:
        ret = JSValueMakeNull(ctx);
        break;
    }

    return ret;
}

JSValueRef FrameLoaderClientManx::jsFunctionCallbackWithDelegate(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
    return gFrameLoaderClient->jsDelegate(ctx, function, argumentCount, arguments);
//    return function;
}

JSValueRef FrameLoaderClientManx::jsFunctionCallback(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
    return function;
}

void FrameLoaderClientManx::setJSObject(WebViewJavaScriptObject* parentObj, JSObjectRef parentObjRef)
{
    if (!parentObj)
        return;

    JSGlobalContextRef context = toGlobalRef(m_frame->script()->globalObject(mainThreadNormalWorld())->globalExec());

    WebViewJavaScriptObject* child = 0;
    int index = 0;
    while (child = parentObj->childObjectAtIndex(index)) {
        JSDOMWindow* domWindow = m_frame->script()->globalObject(mainThreadNormalWorld());
        if (!parentObjRef)
            parentObjRef = toRef(domWindow);

        if (!child->auth(m_cert, domWindow->impl()->document()->url().host().utf8().data())) {
            index++;
            continue;
        }

        switch (child->objectType()) {
        case OBJECT_TYPE_OBJECT:
            {
                JSStringRef objName = JSStringCreateWithUTF8CString(child->baseUrl());
                JSObjectRef obj = JSObjectMake(context, 0, 0);
                JSObjectSetProperty(context, parentObjRef, objName, obj, kJSPropertyAttributeReadOnly, 0);
                JSStringRelease(objName);
                setJSObject(child, obj);
            }
            break;
        case OBJECT_TYPE_FUNCTION:
            {
                JSStringRef funcName = JSStringCreateWithUTF8CString(child->baseUrl());
                if (child->delegate()) {
                    JSObjectRef func = JSObjectMakeFunctionWithCallback(context, funcName, jsFunctionCallbackWithDelegate);
                    JSObjectSetProperty(context, parentObjRef, funcName, func, kJSPropertyAttributeReadOnly, 0);
                } else {
                    JSObjectRef func = JSObjectMakeFunctionWithCallback(context, funcName, jsFunctionCallback);
                    JSObjectSetProperty(context, parentObjRef, funcName, func, kJSPropertyAttributeReadOnly, 0);
                }
                JSStringRelease(funcName);
            }
            break;
        }
        index++;
    }
}

void FrameLoaderClientManx::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
{
    if (world != mainThreadNormalWorld())
        return;

    ASSERT(m_frame);

    Settings* settings = m_frame->settings();
    if (!settings || !settings->isScriptEnabled())
        return;

    gFrameLoaderClient = this;

    JSGlobalContextRef context = toGlobalRef(m_frame->script()->globalObject(mainThreadNormalWorld())->globalExec());
    JSDOMWindow* domWindow = m_frame->script()->globalObject(mainThreadNormalWorld());
    JSObjectRef windowObject = toRef(domWindow);
    ASSERT(windowObject);

    // Add window.external
    JSStringRef objName = JSStringCreateWithUTF8CString("external");
    JSObjectRef obj = JSObjectMake(context, 0, 0);
    JSObjectSetProperty(context, windowObject, objName, obj, kJSPropertyAttributeReadOnly, 0);
    JSStringRelease(objName);

    setJSObject(m_webView->javaScriptObj());

    m_webView->client().didWindowObjectCleared((void*)m_frame, (void*)context, (void*)windowObject);
}

void FrameLoaderClientManx::documentElementAvailable()
{
    notImplemented();
}

void FrameLoaderClientManx::didPerformFirstNavigation() const
{
    notImplemented();
}

void FrameLoaderClientManx::registerForIconNotification(bool listen)
{
    notImplemented();
}

PassRefPtr<FrameNetworkingContext> FrameLoaderClientManx::createNetworkingContext()
{
    return FrameNetworkingContextManx::create(m_frame);
}

}
